#include "mycoroutine_coroutine.h"
#include "base.h"
#include "coroutine.h"

ZEND_BEGIN_ARG_INFO_EX(arginfo_mycoroutine_coroutine_create, 0, 0, 1)
    ZEND_ARG_CALLABLE_INFO(0, func, 0)
    ZEND_ARG_VARIADIC_INFO(0, params)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_mycoroutine_coroutine_resume, 0, 0, 1)
    ZEND_ARG_INFO(0, cid)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_mycoroutine_coroutine_isExist, 0, 0, 1)
    ZEND_ARG_INFO(0, cid)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_mycoroutine_coroutine_void, 0, 0, 0)
ZEND_END_ARG_INFO()

PHP_METHOD(mycoroutine_coroutine_util, create){
	zend_fcall_info fci;
    zend_fcall_info_cache fcc;
	zval result;

    ZEND_PARSE_PARAMETERS_START(1, -1)
        Z_PARAM_FUNC(fci, fcc)
        Z_PARAM_VARIADIC('*', fci.params, fci.param_count)
    ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);

	long cid = PHPCoroutine_create(&fcc,fci.param_count,fci.params);
	RETURN_LONG(cid);
}

PHP_METHOD(mycoroutine_coroutine_util, yield){
	Coroutine *co = get_current();
	long cid = coroutine_get_cid(co);
	Coroutine_array_insert(cid,co);
	coroutine_yield(co);
}

PHP_METHOD(mycoroutine_coroutine_util, resume){
	long cid;
    if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &cid) == FAILURE)
    {
        RETURN_FALSE;
    }

	Coroutine *co = Coroutine_array_find(&coroG.user_yield_coros,cid);
	if(!co){
		php_error_docref(NULL, E_WARNING, "resume error");
        RETURN_FALSE;
	}

	Coroutine_array_erase(coroG.user_yield_coros.coroutines,cid);
	coroutine_resume(co);
}

PHP_METHOD(mycoroutine_coroutine_util, getCid){
	Coroutine *co = get_current();
	if(!co){
		RETURN_LONG(-1);
	}
	RETURN_LONG(coroutine_get_cid(co));
}

PHP_METHOD(mycoroutine_coroutine_util, isExist){
	long cid;
	bool is_exist;
	Coroutine *co;

	ZEND_PARSE_PARAMETERS_START(1, 1)
        Z_PARAM_LONG(cid)
    ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);

	co = Coroutine_array_find(&coroG.coroutines,cid);
	is_exist = (co != NULL);

	RETURN_BOOL(is_exist);
}

const zend_function_entry mycoroutine_coroutine_util_methods[] =
{
    PHP_ME(mycoroutine_coroutine_util, create, arginfo_mycoroutine_coroutine_create, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
    PHP_ME(mycoroutine_coroutine_util, yield, arginfo_mycoroutine_coroutine_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
	PHP_ME(mycoroutine_coroutine_util, resume, arginfo_mycoroutine_coroutine_resume, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
    PHP_ME(mycoroutine_coroutine_util, getCid, arginfo_mycoroutine_coroutine_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
	PHP_ME(mycoroutine_coroutine_util, isExist, arginfo_mycoroutine_coroutine_isExist, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
	PHP_FE_END
};

/**
 * Define zend class entry
 */
zend_class_entry mycoroutine_coroutine_ce;
zend_class_entry *mycoroutine_coroutine_ce_ptr;

void mycoroutine_coroutine_util_init()
{
    INIT_NS_CLASS_ENTRY(mycoroutine_coroutine_ce, "Mycoroutine", "Coroutine", mycoroutine_coroutine_util_methods);
  mycoroutine_coroutine_ce_ptr = zend_register_internal_class(&mycoroutine_coroutine_ce TSRMLS_CC); // Registered in the Zend Engine
}
